package com.newsee.remote.common.utils.tools;

import org.apache.commons.collections.CollectionUtils;
import org.apache.commons.collections.MapUtils;
import org.apache.commons.lang3.StringUtils;

import java.util.*;


public class CcUtils {
    /**
     * 获取集合的第一个元素
     * 
     * @param dataList
     *            非空集合
     * @param <V>
     *            元素类型
     * @return 集合的第一个元素
     */
    public static <V> V first(Collection<V> dataList) {
        return first(dataList, Boolean.FALSE);
    }

    /**
     * 获取集合的第一个元素，若集合为null则返回null
     * 
     * @param dataList
     *            集合
     * @param <V>
     *            元素类型
     * @param nullCheck
     *            集合空校验
     * @return 集合的第一个元素，或null
     */
    public static <V> V first(Collection<V> dataList, Boolean nullCheck) {
        if (Boolean.TRUE.equals(nullCheck) && CollectionUtils.isEmpty(dataList)) {
            return null;
        }
        return dataList.iterator().next();
    }

    /**
     * 获取集合的第一个元素键，若集合为null则返回null
     *
     * @param dataMap
     *            集合
     * @param <K>
     *            键类型
     * @param <V>
     *            值类型
     * @return 集合的第一个元素键，或null
     */
    public static <K, V> K firstKey(Map<K, V> dataMap) {
        return firstKey(dataMap, Boolean.FALSE);
    }

    /**
     * 获取集合的第一个元素键，若集合为null则返回null
     * 
     * @param dataMap
     *            集合
     * @param nullCheck
     *            集合空校验
     * @param <K>
     *            键类型
     * @param <V>
     *            值类型
     * @return 集合的第一个元素键，或null
     */
    public static <K, V> K firstKey(Map<K, V> dataMap, Boolean nullCheck) {
        if (Boolean.TRUE.equals(nullCheck) && MapUtils.isEmpty(dataMap)) {
            return null;
        }
        return dataMap.keySet().iterator().next();
    }

    /**
     * 获取集合的第一个元素值，若集合为null则返回null
     *
     * @param dataMap
     *            集合
     * @param <K>
     *            键类型
     * @param <V>
     *            值类型
     * @return 集合的第一个元素值，或null
     */
    public static <K, V> V firstValue(Map<K, V> dataMap) {
        return firstValue(dataMap, Boolean.FALSE);
    }

    /**
     * 获取集合的第一个元素值，若集合为null则返回null
     *
     * @param dataMap
     *            集合
     * @param nullCheck
     *            集合空校验
     * @param <K>
     *            键类型
     * @param <V>
     *            值类型
     * @return 集合的第一个元素值，或null
     */
    public static <K, V> V firstValue(Map<K, V> dataMap, Boolean nullCheck) {
        if (Boolean.TRUE.equals(nullCheck) && MapUtils.isEmpty(dataMap)) {
            return null;
        }
        return dataMap.values().iterator().next();
    }

    /**
     * 将列表字符串转换成列表
     * 
     * @param listStr
     *            列表字符串
     * @param separator
     *            分隔符
     * @param converter
     *            数据转换器
     * @param <T>
     *            目标类型
     * @return 列表
     */
    public static <T> List<T> toList(String listStr, String separator, Converter<String, T> converter) {
        List<T> dataList = new ArrayList<>();
        if (StringUtils.isBlank(listStr) || StringUtils.isBlank(separator)) {
            return dataList;
        }

        String[] strList = StringUtils.split(listStr, separator);
        if (strList != null && strList.length > 0) {
            for (String str: strList) {
                dataList.add(converter.convert(str));
            }
        }

        return dataList;
    }

    /**
     * 从列表中挑选符合条件的第一个项目
     *
     * @param dataList
     *            数据List
     * @param condition
     *            挑选条件
     * @param <D>
     *            数据类型
     * @return 符合条件的第一个项目
     */
    public static <D> D pickFirst(Collection<D> dataList, Condition<D> condition) {
        D retVal = null;
        if (CollectionUtils.isNotEmpty(dataList)) {
            for (D data: dataList) {
                if (condition.isMatch(data)) {
                    retVal = data;
                }
            }
        }
        return retVal;
    }

    /**
     * 从列表中挑选符合条件的项目
     * 
     * @param dataList
     *            数据List
     * @param condition
     *            挑选条件
     * @param <D>
     *            数据类型
     * @return 符合条件的项目
     */
    public static <D> List<D> pick(Collection<D> dataList, Condition<D> condition) {
        List<D> retVal = new ArrayList<>();
        if (CollectionUtils.isNotEmpty(dataList)) {
            for (D data: dataList) {
                if (condition.isMatch(data)) {
                    retVal.add(data);
                }
            }
        }
        return retVal;
    }

    /**
     * 将list转换成map
     *
     * @param dataList
     *            数据List
     * @param kGetter
     *            key获取方式
     * @param vGetter
     *            value获取方式
     * @param condition
     *            插入条件
     * @param <K>
     *            健类型
     * @param <V>
     *            值类型
     * @param <D>
     *            原数据类型
     * @return 转换后的map
     */
    public static <K, V, D> Map<K, V> toMap(Collection<D> dataList, Getter<K, D> kGetter, Getter<V, D> vGetter,
        Condition<D> condition) {
        Map<K, V> retVal = new HashMap<>();
        if (CollectionUtils.isNotEmpty(dataList)) {
            for (D data: dataList) {
                if (condition == null || condition.isMatch(data)) {
                    K key = kGetter.get(data);
                    V value = vGetter.get(data);
                    retVal.put(key, value);
                }
            }
        }
        return retVal;
    }

    /**
     * 将list转换成map
     * 
     * @param dataList
     *            数据List
     * @param getter
     *            key获取方式
     * @param condition
     *            插入条件
     * @param <K>
     *            健类型
     * @param <V>
     *            值类型
     * @return 转换后的map
     */
    public static <K, V> Map<K, V> toMap(Collection<V> dataList, Getter<K, V> getter, Condition<V> condition) {
        return toMap(dataList, getter, data -> data, condition);
    }

    /**
     * 将list转换成map
     * 
     * @param dataList
     *            数据List
     * @param kGetter
     *            key获取方式
     * @param vGetter
     *            value获取方式
     * @param <K>
     *            健类型
     * @param <V>
     *            值类型
     * @param <D>
     *            原数据类型
     * @return 转换后的map
     */
    public static <K, V, D> Map<K, V> toMap(Collection<D> dataList, Getter<K, D> kGetter, Getter<V, D> vGetter) {
        return toMap(dataList, kGetter, vGetter, null);
    }

    /**
     * 将list转换成map
     *
     * @param dataList
     *            数据List
     * @param getter
     *            key获取方式
     * @param <K>
     *            健类型
     * @param <V>
     *            值类型
     * @return 转换后的map
     */
    public static <K, V> Map<K, V> toMap(Collection<V> dataList, Getter<K, V> getter) {
        return toMap(dataList, getter, data -> data, null);
    }

    /**
     * 将list转换成map
     * 
     * @param dataList
     *            数据List
     * @param kGetter
     *            key获取方式
     * @param vGetter
     *            value获取方式
     * @param condition
     *            插入条件
     * @param <K>
     *            健类型
     * @param <V>
     *            值类型
     * @param <D>
     *            原数据类型
     * @return 转换后的map
     */
    public static <K, V, D> Map<K, List<V>> toMapList(Collection<D> dataList, Getter<K, D> kGetter,
        Getter<V, D> vGetter, Condition<D> condition) {
        Map<K, List<V>> retVal = new HashMap<>();
        if (CollectionUtils.isNotEmpty(dataList)) {
            for (D data: dataList) {
                if (condition == null || condition.isMatch(data)) {
                    K key = kGetter.get(data);
                    if (key != null) {
                        List<V> valueList = retVal.computeIfAbsent(key, k -> new ArrayList<>());
                        V value = vGetter.get(data);
                        if (value != null && !valueList.contains(value)) {
                            valueList.add(value);
                        }
                    }
                }
            }
        }
        return retVal;
    }

    /**
     * 将list转换成map
     *
     * @param dataList
     *            数据List
     * @param getter
     *            key获取方式
     * @param condition
     *            插入条件
     * @param <K>
     *            健类型
     * @param <V>
     *            值类型
     * @return 转换后的map
     */
    public static <K, V> Map<K, List<V>> toMapList(Collection<V> dataList, Getter<K, V> getter,
        Condition<V> condition) {
        return toMapList(dataList, getter, data -> data, condition);
    }

    /**
     * 将list转换成map
     * 
     * @param dataList
     *            数据List
     * @param kGetter
     *            key获取方式
     * @param vGetter
     *            value获取方式
     * @param <K>
     *            健类型
     * @param <V>
     *            值类型
     * @param <D>
     *            原数据类型
     * @return 转换后的map
     */
    public static <K, V, D> Map<K, List<V>> toMapList(Collection<D> dataList, Getter<K, D> kGetter,
        Getter<V, D> vGetter) {
        return toMapList(dataList, kGetter, vGetter, null);
    }

    /**
     * 将list转换成map
     *
     * @param dataList
     *            数据List
     * @param getter
     *            key获取方式
     * @param <K>
     *            健类型
     * @param <V>
     *            值类型
     * @return 转换后的map
     */
    public static <K, V> Map<K, List<V>> toMapList(Collection<V> dataList, Getter<K, V> getter) {
        return toMapList(dataList, getter, data -> data, null);
    }

    /**
     * 收集list中的关键数据
     * 
     * @param dataList
     *            数据list
     * @param getter
     *            关键数据获取方式
     * @param condition
     *            关键数据获取调条件
     * @param <R>
     *            关键数据类型
     * @param <D>
     *            待收集数据类型
     * @return 关键数据集
     */
    public static <R, D> List<R> collect(Collection<D> dataList, Getter<R, D> getter, Condition<D> condition) {
        List<R> retVal = new ArrayList<>();
        if (CollectionUtils.isNotEmpty(dataList)) {
            for (D data: dataList) {
                R resource = getter.get(data);
                if (condition == null || condition.isMatch(data)) {
                    if (resource != null && !retVal.contains(resource)) {
                        retVal.add(resource);
                    }
                }
            }
        }
        return retVal;
    }

    /**
     * 收集list中的关键数据
     *
     * @param dataList
     *            数据list
     * @param getter
     *            关键数据获取方式
     * @param <R>
     *            关键数据类型
     * @param <D>
     *            待收集数据类型
     * @return 关键数据集
     */
    public static <R, D> List<R> collect(Collection<D> dataList, Getter<R, D> getter) {
        return collect(dataList, getter, null);
    }

    /**
     * 对list进行去重
     * 
     * @param dataList
     *            数据list
     * @param getter
     *            数据指纹获取方法
     * @param <D>
     *            数据类型
     * @return 去重后的列表
     */
    public static <D> List<D> distinct(Collection<D> dataList, DataKeyGetter<D> getter) {
        Map<String, D> dataMap = new HashMap<>();
        if (CollectionUtils.isNotEmpty(dataList)) {
            for (D data: dataList) {
                dataMap.put(getter.getKey(data), data);
            }
        }
        return new ArrayList<>(dataMap.values());
    }

    /**
     * 分割列表
     * 
     * @param dataList
     *            完整列表
     * @param size
     *            分割后的大小
     * @param <D>
     *            数据类型
     * @return 分割后的列表
     */
    public static <D> List<List<D>> splitList(List<D> dataList, int size) {
        List<List<D>> dataListList = new ArrayList<>();
        if (CollectionUtils.isNotEmpty(dataList)) {
            int fromIndex = 0;
            int toIndex = size < dataList.size() ? size : dataList.size();
            while (fromIndex < dataList.size() && toIndex > fromIndex) {
                dataListList.add(dataList.subList(fromIndex, toIndex));
                fromIndex = toIndex;
                toIndex += size;
                if (toIndex > dataList.size()) {
                    toIndex = dataList.size();
                }
            }
        }
        return dataListList;
    }

    public interface Getter<R, D> {
        R get(D data);
    }

    public interface Condition<D> {
        boolean isMatch(D data);
    }

    public interface Converter<F, T> {
        T convert(F data);
    }

    public interface DataKeyGetter<D> {
        String getKey(D data);
    }
}
